#!/usr/bin/env python3
# batch_tts_download.py
import asyncio
import os
import random
import sys
from pathlib import Path
from urllib.parse import quote_plus

import aiofiles
import aiohttp
from tqdm.asyncio import tqdm_asyncio

# ------------------ 常量 ------------------
TXT_FILE      = "data.txt"
DOWNLOAD_DIR  = Path("download")
BASE_URL      = "https://user.api.hudunsoft.com/v1/alivoice/texttoaudio"

BASE_PAYLOAD = {
    "client": "web",
    "source": "335",
    "soft_version": "V4.4.0.0",
    "device_id": "5006183292434dbf98e2886ab3eda63c",
    "bgid": "0",
    "bg_volume": "5",
    "format": "mp3",
    "volume": "4",
    "speech_rate": "5",
    "pitch_rate": "4",
    "token": "5006183292434dbf98e2886ab3eda63c",
    "bg_url": ""
}

CONCURRENCY = 10
semaphore   = asyncio.Semaphore(CONCURRENCY)

# ------------------ 工具函数 ------------------
async def fetch_text_lines() -> list[str]:
    if not os.path.isfile(TXT_FILE):
        raise FileNotFoundError(f"{TXT_FILE} 不存在")
    async with aiofiles.open(TXT_FILE, "r", encoding="utf-8") as f:
        lines = [line.strip() for line in await f.readlines()]
    return [l for l in lines if l]

async def download_one(session: aiohttp.ClientSession, text: str, voice: str) -> None:
    async with semaphore:
        payload = BASE_PAYLOAD.copy()
        payload.update({"text": text, "title": text, "voice": voice})

        async with session.post(BASE_URL, data=payload) as resp:
            resp.raise_for_status()
            json_data = await resp.json()

        if json_data.get("code") != 0:
            raise RuntimeError(f"接口返回错误: {json_data}")

        file_url = json_data["data"]["file_link"]
        file_path = DOWNLOAD_DIR / f"{text}.mp3"

        async with session.get(file_url) as d_resp:
            d_resp.raise_for_status()
            async with aiofiles.open(file_path, "wb") as f:
                async for chunk in d_resp.content.iter_chunked(1024 * 64):
                    await f.write(chunk)

        await asyncio.sleep(random.randint(3, 8))

async def main(voice: str):
    DOWNLOAD_DIR.mkdir(exist_ok=True)
    lines = await fetch_text_lines()
    if not lines:
        print("data.txt 为空")
        return

    async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=60)) as session:
        tasks = [download_one(session, line, voice) for line in lines]
        await tqdm_asyncio.gather(*tasks, desc="下载进度")

# ------------------ 入口 ------------------
# pyinstaller -F -c -i icon.png --hidden-import aiofiles --hidden-import aiohttp --hidden-import tqdm app.py
if __name__ == "__main__":
    # 1. 输入音色
    print("语音合成网站【https://www.luyinzhushou.com/text2voice】")
    voice_input = input("输入音色 voice（默认 sijia）：").strip()
    voice = voice_input if voice_input else "sijia"

    # 2. Windows 下避免事件循环关闭报错
    if sys.platform.startswith("win"):
        asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

    try:
        asyncio.run(main(voice))
    except KeyboardInterrupt:
        print("\n用户中断")